package core.proto.search;
import core.proto.*;
import static app.constants.CollabVizConstants.*;

import java.awt.Point;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.Set;

import javax.swing.JTree;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.tree.DefaultMutableTreeNode;

import org.apache.commons.io.FilenameUtils;

import core.proto.CaseNode;
import core.proto.FileTree;
import core.proto.FilterTreeModel;
import core.proto.IconData;
import core.proto.Util;



/**
 * Reacts to user typing text into the JComponent whose document model 
 * we are listening on, and in response perform a search on the lucene index. 
 */
public class FileTreeSearchDocumentListener implements DocumentListener {

	static final int HIDE_NONMATCHES = 0;
	static final int GRAY_NONMATCHES = 1;
	static final int NONMATCH_DISPLAY_MODE = HIDE_NONMATCHES;

	boolean isSearchStarted;
	LuceneSearchHelper luceneSearcher;
	FileTree fileTree;

	
	public FileTreeSearchDocumentListener(FileTree fileTree){
		isSearchStarted = false;
		this.fileTree = fileTree;
		try {
			// Assume that index directory is downloaded onto the local computer.
			luceneSearcher = new LuceneSearchHelper(new File(INDEX_DIRECTORY));
		} catch (IOException e) {
			throw new Error(e);
		}
	}

	@Override
	public void changedUpdate(DocumentEvent de) {
		// No op. 
	}

	@Override
	public void insertUpdate(DocumentEvent de) {
		try {
			search(de.getDocument().getText(0, de.getDocument().getLength()));
		} catch (BadLocationException e) {
			throw new Error(e);
		}
	}

	@Override
	public void removeUpdate(DocumentEvent de) {
		try {
			search(de.getDocument().getText(0, de.getDocument().getLength()));
		} catch (BadLocationException e) {
			throw new Error(e);
		}
	}

	Set<String> searchWithLucene(String queryString){
		Set<String> result;
		try {
			result = luceneSearcher.search(queryString);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			throw new Error(e);
		}
	}

	void markHits (Set<String> hits, JTree tree) {
		Enumeration e = ((DefaultMutableTreeNode) tree.getModel().getRoot()).breadthFirstEnumeration();
		while (e.hasMoreElements()) {
			DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) e.nextElement();
			IconData icon = (IconData) treeNode.getUserObject();
			CaseNode node = (CaseNode) icon.getObject();
			if (! hits.contains(FilenameUtils.getBaseName(node.getAbsolutePath()))){
				icon.setIsSearchHit(false);
			} else {
				icon.setIsSearchHit(true);
			}
		}
	}

	void unmarkHits (JTree tree) {
		Enumeration e = ((DefaultMutableTreeNode) tree.getModel().getRoot()).breadthFirstEnumeration();
		while (e.hasMoreElements()) {
			DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) e.nextElement();
			IconData icon = (IconData) treeNode.getUserObject();
			icon.setIsSearchHit(true);
		}
	}

	void search(String searchText){
		JTree myTree = fileTree.tree;
		// If it begins searching, save current tree expanded status
		if (!isSearchStarted) {
			fileTree.saveTreeExpandedStatus();
			isSearchStarted = true;
		}

		// collapse the tree before searching
		for(int i=myTree.getRowCount()-1; i>=0; --i){
			myTree.collapseRow(i);
		}

		// absolute paths of matching documents. 
		Set<String> searchResult;

		boolean isBlankSearch = searchText.trim().equals("");

		if (isBlankSearch){
			if (NONMATCH_DISPLAY_MODE == HIDE_NONMATCHES){
				((FilterTreeModel) myTree.getModel()).setAcceptedPaths(null);
			} else if (NONMATCH_DISPLAY_MODE == GRAY_NONMATCHES){
				unmarkHits(myTree);
			}
			fileTree.restoreExpandedTreeStatus();
			isSearchStarted = false;
		} else {
			searchResult = searchWithLucene(searchText);
			if (NONMATCH_DISPLAY_MODE == HIDE_NONMATCHES){
				((FilterTreeModel) myTree.getModel()).setAcceptedPaths(searchResult);
			} else if (NONMATCH_DISPLAY_MODE == GRAY_NONMATCHES){
				markHits(searchResult, myTree);
			}

			fileTree.expandTree();
		}
		myTree.repaint();
	}
}
